﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VirtualTournaments.Business.Tournaments.Exceptions;

namespace VirtualTournaments.Business.Tournaments
{
    public class AllAgainstAllTournament : Tournament
    {
        private Standings _standings;
        private bool _roundFinished;

        private static Random RANDOM_NUMBERS_GENERATOR = new Random();
        private static int MINIMUN_TEAM_NUMBER = 3;
        private static int MAXIMUM_TEAM_NUMBER = 20;
        
        public AllAgainstAllTournament(IEnumerable<Team> teams) :
            this(null, teams) { }

        public AllAgainstAllTournament(String name, IEnumerable<Team> teams) :
            this(name, teams, MatchFactory.GetInstance()) { }

        public AllAgainstAllTournament(IEnumerable<Team> teams, MatchFactory factory) :
            this(null, teams, factory)
        { }

        public AllAgainstAllTournament(String name, IEnumerable<Team> teams, MatchFactory factory) :
            base(name, teams, factory)
        {
            if (teams.Count() < MINIMUN_TEAM_NUMBER || teams.Count() > MAXIMUM_TEAM_NUMBER)
                throw new InvalidTeamsNumberException();
            if (this.Fixture == null)
            {
                this.Fixture = new Fixture(this);
                this.Fixture.GenerateAllAgainstAll(teams, factory);
            }
            Standings = new Standings(teams);
        }

        public virtual Standings Standings
        {
            get { return _standings; }
            protected set { _standings = value; }
        }

        protected bool RoundFinished
        {
            get { return _roundFinished; }
            set { _roundFinished = value; }
        }

        public override void PlayNextJourney()
        {
            if (HasFinished())
                throw new FinishedTournamentException();

            List<MatchResult> results = new List<MatchResult>();

            if (RoundFinished)
                Standings = new Standings(Teams);
            foreach (Match match in GetNextJourney())
                results.Add(match.Play());
            Standings.Update(results);
            RoundFinished = (++LastJourneyNumber >= Fixture.JourneysCount());
            if (RoundFinished)
                DefinePositions();
        }

        private void DefinePositions()
        {
            List<TeamStatics> firstTeams = Standings.GetTeamsStatics(1).ToList();
            if (firstTeams.Count == 1)
            {
                IsFinished = true;
                First = firstTeams[0].Team;
                List<TeamStatics> secondTeams = Standings.GetTeamsStatics(2).ToList();
                if (secondTeams.Count == 1)
                {
                    Second = secondTeams[0].Team;
                    if (TeamsList.Count > 3)
                        Third = SelectTeam(Standings.GetTeamsStatics(3).ToList());
                }
                else
                {
                    Second = SelectTeam(secondTeams);
                    Third = SelectTeam(secondTeams);
                }
            }
            else
            {
                if (TeamsList.Count > 2 && firstTeams.Count() == 2)
                    Third = SelectTeam(Standings.GetTeamsStatics(3).ToList());
                TeamsList = new List<Team>();
                foreach (TeamStatics Statics in firstTeams)
                    TeamsList.Add(Statics.Team);
                Fixture.GenerateAllAgainstAll(Teams, Factory);
            }
        }

        private Team SelectTeam(List<TeamStatics> teams)
        {
            int teamIndex = RANDOM_NUMBERS_GENERATOR.Next(teams.Count);
            Team team = teams[teamIndex].Team;
            teams.RemoveAt(teamIndex);
            return team;
        }
    }
}
